Во-первых, позвольте мне остановиться на нескольких терминах. Если вы просто хотите, чтобы на ваш вопрос ответили, прокрутите вниз до пункта «Ответ на ваш вопрос».
Определения
Идентификатор объекта : Когда вы создаете объект, вы можете назначить его переменной. Затем вы можете также назначить его другой переменной. И еще один.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
В этом случае cancel
, close
и dismiss
все ссылаются на один и тот же объект в памяти. Вы создали только один Button
объект, и все три переменные ссылаются на этот один объект. Мы говорим, что cancel
, close
и dismiss
все относятся к идентичным объектам; то есть они ссылаются на один единственный объект.
Равенство объектов : Когда вы сравниваете два объекта, вам, как правило, не важно, относится ли он к точному одному и тому же объекту в памяти. С помощью равенства объектов вы можете определить свои собственные правила сравнения двух объектов. Когда вы пишете if a == b:
, вы, по сути, говорите if a.__eq__(b):
. Это позволяет вам определить метод __eq__
для a
, чтобы вы могли использовать собственную логику сравнения.
Обоснование сравнений на равенство
Обоснование: Два объекта имеют одинаковые данные, но не идентичны. (Они не один и тот же объект в памяти.)
Пример: Строки
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Примечание: здесь я использую строки Unicode, потому что Python достаточно умен, чтобы повторно использовать обычные строки без создания новых в памяти.
Здесь у меня есть две строки Unicode, a
и b
. У них одинаковое содержание, но они не являются одним и тем же объектом в памяти. Однако, когда мы сравниваем их, мы хотим, чтобы они сравнивались на равных. Здесь происходит то, что в объекте Unicode реализован метод __eq__
.
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Примечание: __eq__
на unicode
определенно реализовано более эффективно, чем эта.
Обоснование: Два объекта имеют разные данные, но считаются одним и тем же объектом, если некоторые ключевые данные совпадают.
Пример: Большинство типов данных модели
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Здесь у меня есть два монитора Dell, a
и b
. Они имеют одинаковую марку и модель. Однако они не имеют одинаковых данных и не являются одним и тем же объектом в памяти. Однако, когда мы сравниваем их, мы хотим, чтобы они сравнивались на равных. Здесь происходит то, что объект Monitor реализует метод __eq__
.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
Отвечая на ваш вопрос
При сравнении с None
всегда используйте is not
. Ни один из них не является синглтоном в Python - в памяти только один его экземпляр.
Сравнивая identity , это можно сделать очень быстро. Python проверяет, имеет ли объект, на который вы ссылаетесь, тот же адрес памяти, что и глобальный объект None, - очень и очень быстрое сравнение двух чисел.
Сравнивая равенство , Python должен выяснить, есть ли у вашего объекта метод __eq__
. Если это не так, он проверяет каждый суперкласс в поисках метода __eq__
. Если он находит, Python вызывает его. Это особенно плохо, если метод __eq__
медленный и не сразу возвращается, когда замечает, что другой объект - None
.
Вы не внедрили __eq__
? Тогда Python, вероятно, найдет метод __eq__
в object
и использует его вместо этого - который в любом случае просто проверяет подлинность объекта.
При сравнении большинства других вещей в Python вы будете использовать !=
.